package io.itit.ecp.admin.provide.action.controller;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.enums.CarbonQuotaInputTypeEnums;
import io.itit.ecp.admin.common.enums.IMeterDeviceEnums;
import io.itit.ecp.admin.common.enums.ProductTypeActiveStatus;
import io.itit.ecp.admin.provide.action.resp.*;
import io.itit.ecp.admin.provide.helper.SceneHelper;
import io.itit.ecp.admin.server.entity.*;
import io.itit.ecp.admin.server.service.*;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.itit.grass.common.server.entity.BaseEntity;
import io.itit.grass.common.server.utils.ConvertUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * @Author：Roy
 * @Description：碳排报告控制类
 * @Date：Create by 2023-11-23 11:46:13
 */
@Api(tags = "碳排报告")
@RestController
@RequestMapping("/ecp-admin/carbonEmissionReport/")
public class CarbonEmissionReportController {

    @Resource
    private IEnergyDataService energyDataService;

    @Resource
    private ICarbonSinkDataService carbonSinkDataService;

    @Resource
    private IEnergyConsumptionTypeService energyConsumptionTypeService;

    @Resource
    private ICarbonEmissionRangeService carbonEmissionRangeService;

    @Resource
    private IActivityCarbonEmissionService activityCarbonEmissionService;

    /**
     * 总览数据查询
     */
    @ApiOperation("总览数据查询")
    @GetMapping("overviewdata")
    public ResultResp<Map<String, Object>> overviewData(String sceneProjectId,
                                                        String sceneEdificeId,
                                                        String sceneFloorId,
                                                        String sceneRoomId,
                                                        String statisticsMode,
                                                        String solidifyDateStart, String solidifyDateEnd) {

        QueryWrapper<EnergyDataEntity> wrapper = new QueryWrapper<>();
        wrapper.select("SUM(standard_coal) as standardCoal");
        wrapper.eq(StringUtils.hasLength(sceneProjectId), "scene_project_id", sceneProjectId);
        wrapper.eq(StringUtils.hasLength(sceneEdificeId), "scene_edifice_id", sceneEdificeId);
        wrapper.eq(StringUtils.hasLength(sceneFloorId), "scene_floor_id", sceneFloorId);
        wrapper.eq(StringUtils.hasLength(sceneRoomId), "scene_room_id", sceneRoomId);
        LocalDateTime start = null;
        LocalDateTime end = LocalDateTime.now();
        if (StringUtils.hasLength(statisticsMode)) {
            start = getStartDate(statisticsMode, solidifyDateStart);
            end = getEndDate(statisticsMode, solidifyDateEnd);
        }
        wrapper.ge(Objects.nonNull(start), "solidify_date", start);
        wrapper.le(Objects.nonNull(end), "solidify_date", end);

        Map<String, Object> result = new HashMap<>();
        result.put("startDate", Objects.isNull(start) ? null : start.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
        result.put("endDate", end.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
        List<Map<String, Object>> list = energyDataService.getBaseMapper().selectMaps(wrapper);
        BigDecimal energyConsumptionTotal = BigDecimal.ZERO; //  能源使用总量
        if (!list.isEmpty()) {
            Map<String, Object> map = list.get(0);
            if (Objects.nonNull(map)) {
                Object standardCoal = map.get("standardCoal");
                energyConsumptionTotal = Objects.nonNull(standardCoal) ? new BigDecimal(standardCoal.toString()).setScale(2, RoundingMode.HALF_DOWN) : BigDecimal.ZERO;
            }
        }
        result.put("energyConsumptionTotal", energyConsumptionTotal);

        result.put("carbonEmissionsTotal", computeCarbonEmissionData(sceneProjectId, sceneEdificeId, sceneFloorId, sceneRoomId, start, end)); // 碳排放总量
        //  没有选择 sceneEdificeId 时，查询  碳减排总量 和  碳汇总量
        if (!StringUtils.hasLength(sceneEdificeId)) {
            result.put("carbonReductionTotal", computeCarbonReductionTotal(sceneProjectId, start, end));
            result.put("carbonSinkTotal", computeCarbonSinkTotalTotal(sceneProjectId, start, end));
        }
        return ResultResp.success(result);
    }

    @ApiOperation("碳排放因子库查询")
    @GetMapping("carbonEmissionFactor")
    public ResultResp<List<CarbonEmissionFactorResp>> carbonEmissionFactor(String statisticsMode,
                                                                           String solidifyDateStart, String solidifyDateEnd) {
        LocalDateTime start = getStartDate(statisticsMode, solidifyDateStart);
        LocalDateTime end = getEndDate(statisticsMode, solidifyDateEnd);
        return ResultResp.success(buildCarbonEmissionFactorQW(start, end).joinList(CarbonEmissionFactorResp.class));
    }

    @ApiOperation("碳排放总量分析查询")
    @GetMapping("carbonEmissionsAnalysisTotal")
    public ResultResp<Map<String, Object>> carbonEmissionsAnalysisTotal(String sceneProjectId,
                                                                        String sceneEdificeId,
                                                                        String sceneFloorId,
                                                                        String sceneRoomId,
                                                                        String statisticsMode,
                                                                        String solidifyDateStart, String solidifyDateEnd) {
        List<EnergyConsumptionTypeEntity> consumptionTypeEntities = energyConsumptionTypeService.list(new LambdaQueryWrapper<EnergyConsumptionTypeEntity>()
                .eq(EnergyConsumptionTypeEntity::getStatus, "1")
                .orderByAsc(EnergyConsumptionTypeEntity::getCreateTm));
        LocalDateTime start = getStartDate(statisticsMode, solidifyDateStart);
        LocalDateTime end = getEndDate(statisticsMode, solidifyDateEnd);
        List<CarbonEmissionDataResp> emissionDataResps = Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder
                        .add("ecp_tt_energy_data.energy_type_id", "energyTypeId", false)
                        .add("SUM(carbon_emission)", "carbonEmission", false)
                        .add("SUM(standard_coal)", "standardCoal", false)
                )
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .notIn(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), EnergyDataEntity::getSceneRoomId, sceneRoomId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EnergyDataEntity::getSolidifyDate, end)
                .groupBy(EnergyDataEntity::getEnergyTypeId)
                .joinList(CarbonEmissionDataResp.class);
        List<Map<String, Object>> energyTypePieData = new ArrayList<>();
        List<Map<String, Object>> dataList = new ArrayList<>();
        for (EnergyConsumptionTypeEntity energyConsumptionType : consumptionTypeEntities) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", energyConsumptionType.getId());
            map.put("name", energyConsumptionType.getEnergyName());
            BigDecimal value = emissionDataResps
                    .stream()
                    .filter(item -> item.getEnergyTypeId().equals(energyConsumptionType.getId()))
                    .findFirst()
                    .map(CarbonEmissionDataResp::getCarbonEmission).orElse(BigDecimal.ZERO)
                    .setScale(2, RoundingMode.HALF_DOWN);
            map.put("value", value);
            energyTypePieData.add(map);

            Map<String, Object> dataItem = new HashMap<>();
            dataItem.put("id", energyConsumptionType.getId());
            dataItem.put("name", energyConsumptionType.getEnergyName());
            dataItem.put("value", value);
            dataItem.put("standardCoal", emissionDataResps.stream()
                    .filter(item -> item.getEnergyTypeId().equals(energyConsumptionType.getId()))
                    .findFirst().map(CarbonEmissionDataResp::getStandardCoal)
                    .orElse(BigDecimal.ZERO)
                    .setScale(2, RoundingMode.HALF_DOWN));
            dataList.add(dataItem);
        }
        List<CarbonEmissionRangeEntity> rangeEntities = carbonEmissionRangeService.list(new LambdaQueryWrapper<CarbonEmissionRangeEntity>()
                .orderByAsc(CarbonEmissionRangeEntity::getRangeName));
        List<Map<String, Object>> rangePieData = new ArrayList<>();
        for (CarbonEmissionRangeEntity rangeEntity : rangeEntities) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", rangeEntity.getRangeName());
            Set<String> typeIds = consumptionTypeEntities.stream()
                    .filter(item -> item.getRangeId().equals(rangeEntity.getId()))
                    .map(BaseEntity::getId)
                    .collect(Collectors.toSet());
            BigDecimal value = emissionDataResps.stream().filter(item -> typeIds.contains(item.getEnergyTypeId()))
                    .map(CarbonEmissionDataResp::getCarbonEmission).reduce(BigDecimal.ZERO, BigDecimal::add)
                    .setScale(2, RoundingMode.HALF_DOWN);
            map.put("value", value);
            rangePieData.add(map);
        }
        Map<String, Object> result = new HashMap<>();
        result.put("energyTypePieData", energyTypePieData);
        result.put("rangePieData", rangePieData);
        result.put("dataList", dataList);
        result.put("startDate", Objects.isNull(start) ? null : start.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
        result.put("endDate", end.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
        return ResultResp.success(result);
    }


    @ApiOperation("时间碳排放查询")
    @GetMapping("timeCarbonEmissions")
    public ResultResp<List<Map<String, Object>>> timeCarbonEmissions(String sceneProjectId,
                                                                     String sceneEdificeId,
                                                                     String sceneFloorId,
                                                                     String sceneRoomId,
                                                                     String statisticsMode,
                                                                     String solidifyDateStart, String solidifyDateEnd) {
        LocalDateTime start = getStartDate(statisticsMode, solidifyDateStart);
        LocalDateTime end = getEndDate(statisticsMode, solidifyDateEnd);
        List<CarbonEmissionDataResp> emissionDataResps = Joins.of(EnergyDataEntity.class)
                .select(EnergyDataEntity::getEnergyTypeId, EnergyDataEntity::getSolidifyDate, EnergyDataEntity::getCarbonEmission)
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .notIn(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), EnergyDataEntity::getSceneRoomId, sceneRoomId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EnergyDataEntity::getSolidifyDate, end)
                .groupBy(EnergyDataEntity::getEnergyTypeId)
                .orderByAsc(EnergyDataEntity::getSolidifyDate)
                .joinList(CarbonEmissionDataResp.class);
        Map<String, List<CarbonEmissionDataResp>> dateMap = emissionDataResps.stream()
                .collect(Collectors.groupingBy(item -> DateUtil.format(item.getSolidifyDate(), "yyyy-MM-dd"), TreeMap::new, Collectors.toList()));
        List<Map<String, Object>> result = new ArrayList<>(dateMap.size());
        for (Map.Entry<String, List<CarbonEmissionDataResp>> entry : dateMap.entrySet()) {
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("solidifyDate", entry.getKey());
            Map<String, List<CarbonEmissionDataResp>> energyTypeMap = entry.getValue().stream().collect(Collectors.groupingBy(CarbonEmissionDataResp::getEnergyTypeId));
            BigDecimal total = BigDecimal.ZERO;
            for (Map.Entry<String, List<CarbonEmissionDataResp>> energyTypeEntry : energyTypeMap.entrySet()) {
                BigDecimal value = energyTypeEntry.getValue()
                        .stream()
                        .map(CarbonEmissionDataResp::getCarbonEmission)
                        .reduce(BigDecimal.ZERO, BigDecimal::add)
                        .setScale(2, RoundingMode.HALF_DOWN);
                dataMap.put(energyTypeEntry.getKey(), value);
                total = total.add(value);
            }
            dataMap.put("total", total.setScale(2, RoundingMode.HALF_DOWN));
            result.add(dataMap);
        }
        return ResultResp.success(result);
    }


    @ApiOperation("空间碳排放查询")
    @GetMapping("spaceCarbonEmissions")
    public ResultResp<List<Map<String, Object>>> spaceCarbonEmissions(String sceneProjectId,
                                                                      String sceneEdificeId,
                                                                      String sceneFloorId,
                                                                      String sceneRoomId,
                                                                      String statisticsMode,
                                                                      String solidifyDateStart, String solidifyDateEnd) {
        LocalDateTime start = getStartDate(statisticsMode, solidifyDateStart);
        LocalDateTime end = getEndDate(statisticsMode, solidifyDateEnd);
        List<SFunction<EnergyDataEntity, Object>> fields = new ArrayList<>();
        fields.add(EnergyDataEntity::getSceneProjectId);
        if (StringUtils.hasLength(sceneProjectId)) {
            fields.add(EnergyDataEntity::getSceneEdificeId);
        }
        if (StringUtils.hasLength(sceneEdificeId)) {
            fields.add(EnergyDataEntity::getSceneFloorId);
        }
        if (StringUtils.hasLength(sceneRoomId) || StringUtils.hasLength(sceneFloorId)) {
            fields.add(EnergyDataEntity::getSceneRoomId);
        }
        fields.add(EnergyDataEntity::getEnergyTypeId);
        fields.add(EnergyDataEntity::getSolidifyDate);
        fields.add(EnergyDataEntity::getCarbonEmission);
        SFunction<EnergyDataEntity, Object>[] fieldsArray = fields.toArray(new SFunction[0]);
        List<CarbonEmissionDataResp> emissionDataResps = Joins.of(EnergyDataEntity.class)
                .select(fieldsArray)
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .notIn(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), EnergyDataEntity::getSceneRoomId, sceneRoomId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EnergyDataEntity::getSolidifyDate, end)
                .groupBy(EnergyDataEntity::getEnergyTypeId)
                .orderByAsc(EnergyDataEntity::getSolidifyDate)
                .joinList(CarbonEmissionDataResp.class);
        List<Map<String, Object>> result = new ArrayList<>();
        if (StringUtils.hasLength(sceneRoomId) || StringUtils.hasLength(sceneFloorId)) {
            emissionDataResps = SceneHelper.i().setSceneInfo(emissionDataResps);
            Map<String, List<CarbonEmissionDataResp>> projectMap = emissionDataResps.stream()
                    .collect(Collectors.groupingBy(CarbonEmissionDataResp::getSceneRoomId));
            fullSpaceCarbonEmissionsResult(projectMap, result);
        } else if (StringUtils.hasLength(sceneEdificeId)) {
            emissionDataResps = SceneHelper.i().setSceneInfo(emissionDataResps);
            Map<String, List<CarbonEmissionDataResp>> projectMap = emissionDataResps.stream()
                    .collect(Collectors.groupingBy(CarbonEmissionDataResp::getSceneFloorId));
            fullSpaceCarbonEmissionsResult(projectMap, result);
        } else if (StringUtils.hasLength(sceneProjectId)) {
            Map<String, List<CarbonEmissionDataResp>> projectMap = SceneHelper.i().setSceneInfo(emissionDataResps).stream()
                    .collect(Collectors.groupingBy(CarbonEmissionDataResp::getSceneEdificeId));
            fullSpaceCarbonEmissionsResult(projectMap, result);
        } else {
            Map<String, List<CarbonEmissionDataResp>> projectMap = emissionDataResps.stream()
                    .collect(Collectors.groupingBy(CarbonEmissionDataResp::getSceneProjectId));
            fullSpaceCarbonEmissionsResult(projectMap, result);
        }
        return ResultResp.success(result);
    }

    @ApiOperation("活动碳排放查询")
    @GetMapping("activityCarbonEmissions")
    public ResultResp<Map<String, Object>> activityCarbonEmissions(String sceneProjectId,
                                                                   String sceneEdificeId,
                                                                   String sceneFloorId,
                                                                   String sceneRoomId,
                                                                   String statisticsMode,
                                                                   String solidifyDateStart, String solidifyDateEnd) {
        LocalDateTime start = getStartDate(statisticsMode, solidifyDateStart);
        LocalDateTime end = getEndDate(statisticsMode, solidifyDateEnd);
        List<ActivityCarbonEmissionEntity> activityCarbonEmissionEntities = activityCarbonEmissionService.list(new LambdaQueryWrapper<ActivityCarbonEmissionEntity>()
                .orderByAsc(ActivityCarbonEmissionEntity::getActivityName));
        Map<String, Object> resultData = new HashMap<>();
        resultData.put("activityNames", activityCarbonEmissionEntities.stream().map(ActivityCarbonEmissionEntity::getActivityName).collect(Collectors.toList()));
        List<CarbonEmissionDataActivityResp> dataActivityResps = Joins.of(EnergyDataEntity.class)
                .select(EnergyDataEntity::getId, EnergyDataEntity::getSolidifyDate, EnergyDataEntity::getCarbonEmission)
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, EnergyDataEntity::getSceneProjectId)
                .selectAs(SceneProjectEntity::getProjectName, CarbonEmissionDataActivityResp::getProjectName)
                .end()
                .innerJoin(ActivityCarbonEmissionDataEntity.class, ActivityCarbonEmissionDataEntity::getTargetId,
                        EnergyDataEntity::getMeterDeviceId)
                .selectAs(ActivityCarbonEmissionDataEntity::getActivityCarbonId, CarbonEmissionDataActivityResp::getActivityCarbonEmissionId)
                .end()
                .innerJoin(ActivityCarbonEmissionEntity.class, ActivityCarbonEmissionEntity::getId, ActivityCarbonEmissionDataEntity::getActivityCarbonId)
                .selectAs(ActivityCarbonEmissionEntity::getActivityName, CarbonEmissionDataActivityResp::getActivityCarbonEmissionName)
                .end()
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), EnergyDataEntity::getSceneRoomId, sceneRoomId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EnergyDataEntity::getSolidifyDate, end)
                .orderByDesc(EnergyDataEntity::getSolidifyDate).joinList(CarbonEmissionDataActivityResp.class);
        TreeMap<String, List<CarbonEmissionDataActivityResp>> solidifyDateMap = dataActivityResps.stream()
                .collect(Collectors.groupingBy(item -> DateUtil.format(item.getSolidifyDate(), "yyyy-MM-dd"), TreeMap::new, Collectors.toList()));
        List<Map<String, Object>> dataList = new ArrayList<>();
        BigDecimal[] totals = new BigDecimal[activityCarbonEmissionEntities.size()];
        for (Map.Entry<String, List<CarbonEmissionDataActivityResp>> entry : solidifyDateMap.entrySet()) {
            Map<String, Object> map = new HashMap<>();
            map.put("solidifyDate", entry.getKey());
            List<CarbonEmissionDataActivityResp> values = entry.getValue();
            List<BigDecimal> valueList = new ArrayList<>();
            int index = 0;
            for (ActivityCarbonEmissionEntity emissionEntity : activityCarbonEmissionEntities) {
                BigDecimal value = values.stream().filter(item -> StringUtils.pathEquals(emissionEntity.getId(), item.getActivityCarbonEmissionId()))
                        .map(CarbonEmissionDataActivityResp::getCarbonEmission)
                        .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP);
                valueList.add(value);
                totals[index] = totals[index] == null ? value : totals[index].add(value);
                index++;
            }
            map.put("valueList", valueList);
            map.put("total", valueList.stream().reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP));
            dataList.add(map);
        }
        resultData.put("dataList", dataList);
        resultData.put("totals", totals);
        return ResultResp.success(resultData);
    }

    private static void fullSpaceCarbonEmissionsResult(Map<String, List<CarbonEmissionDataResp>> projectMap, List<Map<String, Object>> result) {
        for (Map.Entry<String, List<CarbonEmissionDataResp>> projectEntry : projectMap.entrySet()) {
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("sceneProjectId", projectEntry.getValue().get(0).getSceneProjectId());
            dataMap.put("sceneInfo", projectEntry.getValue().get(0).getSceneInfoName());
            BigDecimal total = BigDecimal.ZERO;
            Map<String, List<CarbonEmissionDataResp>> energyTypeMap = projectEntry.getValue().stream()
                    .collect(Collectors.groupingBy(CarbonEmissionDataResp::getEnergyTypeId));
            for (Map.Entry<String, List<CarbonEmissionDataResp>> energyTypeEntry : energyTypeMap.entrySet()) {
                BigDecimal value = ObjectUtil.defaultIfNull(energyTypeEntry
                                .getValue()
                                .stream()
                                .map(CarbonEmissionDataResp::getCarbonEmission)
                                .reduce(BigDecimal.ZERO, BigDecimal::add), BigDecimal.ZERO)
                        .setScale(2, RoundingMode.HALF_UP);
                dataMap.put(energyTypeEntry.getKey(), value);
                total = total.add(value);
            }
            dataMap.put("total", total.setScale(2, RoundingMode.HALF_UP));
            result.add(dataMap);
        }
    }

    private static JoinLambdaWrapper<CarbonEmissionFactorEntity> buildCarbonEmissionFactorQW(LocalDateTime start, LocalDateTime end) {
        return Joins.of(CarbonEmissionFactorEntity.class)
                .selectAll()
                .leftJoin(EnergyConsumptionTypeEntity.class, EnergyConsumptionTypeEntity::getId, CarbonEmissionFactorEntity::getEnergyTypeId)
                .selectAs(EnergyConsumptionTypeEntity::getEnergyName, CarbonEmissionFactorResp::getEnergyTypeName)
                .end()
                .ge(Objects.nonNull(start), CarbonEmissionFactorEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), CarbonEmissionFactorEntity::getSolidifyDate, end)
                .orderByDesc(CarbonEmissionFactorEntity::getSolidifyDate);
    }

    @ApiOperation("碳减因子库查询")
    @GetMapping("emissionReductionFactor")
    public ResultResp<List<EmissionReductionFactorResp>> emissionReductionFactor(String statisticsMode,
                                                                                 String solidifyDateStart, String solidifyDateEnd) {
        LocalDateTime start = getStartDate(statisticsMode, solidifyDateStart);
        LocalDateTime end = getEndDate(statisticsMode, solidifyDateEnd);
        JoinLambdaWrapper<EmissionReductionFactorEntity> wrapper = Joins.of(EmissionReductionFactorEntity.class)
                .selectAll()
                .leftJoin(EnergyConsumptionTypeEntity.class, EnergyConsumptionTypeEntity::getId, EmissionReductionFactorEntity::getEnergyTypeId)
                .selectAs(EnergyConsumptionTypeEntity::getEnergyName, EmissionReductionFactorResp::getEnergyTypeName)
                .end()
                .ge(Objects.nonNull(start), EmissionReductionFactorEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EmissionReductionFactorEntity::getSolidifyDate, end)
                .orderByDesc(EmissionReductionFactorEntity::getSolidifyDate);
        return ResultResp.success(wrapper.joinList(EmissionReductionFactorResp.class));
    }

    @Resource
    private ICarbonSinkFactorService carbonSinkFactorService;

    @ApiOperation("碳汇因子库查询")
    @GetMapping("carbonSinkFactor")
    public ResultResp<List<CarbonSinkFactorResp>> carbonSinkFactor(String statisticsMode,
                                                                   String solidifyDateStart, String solidifyDateEnd) {
        LocalDateTime start = getStartDate(statisticsMode, solidifyDateStart);
        LocalDateTime end = getEndDate(statisticsMode, solidifyDateEnd);
        LambdaQueryWrapper<CarbonSinkFactorEntity> wrapper = Wrappers.<CarbonSinkFactorEntity>lambdaQuery()
                .ge(Objects.nonNull(start), CarbonSinkFactorEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), CarbonSinkFactorEntity::getSolidifyDate, end)
                .orderByDesc(CarbonSinkFactorEntity::getSolidifyDate);
        return ResultResp.success(ConvertUtils.convert(carbonSinkFactorService.list(wrapper), CarbonSinkFactorResp.class));
    }

    /**
     * 碳减排总量
     */
    private BigDecimal computeCarbonSinkTotalTotal(String sceneProjectId, LocalDateTime start, LocalDateTime end) {
        return ObjectUtil.defaultIfNull(Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder.add("SUM(carbon_emission)", "carbonEmission", false))
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .in(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EnergyDataEntity::getSolidifyDate, end)
                .joinGetOne(BigDecimal.class), BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP);
    }

    /**
     * 碳汇总量
     */
    private BigDecimal computeCarbonReductionTotal(String sceneProjectId, LocalDateTime start, LocalDateTime end) {
        return carbonSinkDataService.computeCarbonReductionTotal(sceneProjectId, start, end);
    }

    private BigDecimal computeCarbonEmissionData(String sceneProjectId, String sceneEdificeId, String sceneFloorId,
                                                 String sceneRoomId, LocalDateTime start, LocalDateTime end) {
        return ObjectUtil.defaultIfNull(Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder.add("SUM(carbon_emission)", "carbonEmission", false))
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .notIn(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), EnergyDataEntity::getSceneRoomId, sceneRoomId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EnergyDataEntity::getSolidifyDate, end)
                .joinGetOne(BigDecimal.class), BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP);
    }

    @SneakyThrows
    public static LocalDateTime getEndDate(String statisticsMode, String solidifyDateEnd) {
        LocalDateTime date = LocalDateTime.now();
        if (StringUtils.hasLength(solidifyDateEnd)) {
            if (StringUtils.pathEquals(statisticsMode, "day")) {
                date = DateUtils.parseDate(solidifyDateEnd, "yyyy", "yyyy-MM", "yyyy-MM-dd")
                        .toInstant().atZone(ZoneId.systemDefault()).toLocalDate().atTime(LocalTime.MAX);
            } else if (StringUtils.pathEquals(statisticsMode, "month")) {
                LocalDate localDate = DateUtils.parseDate(solidifyDateEnd, "yyyy", "yyyy-MM", "yyyy-MM-dd")
                        .toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                date = YearMonth.from(localDate).atEndOfMonth().atTime(LocalTime.MAX);
            }
            if (StringUtils.pathEquals(statisticsMode, "year")) {
                int year = DateUtils.parseDate(solidifyDateEnd, "yyyy", "yyyy-MM", "yyyy-MM-dd")
                        .toInstant().atZone(ZoneId.systemDefault()).getYear();
                date = LocalDate.ofYearDay(year, 1).with(TemporalAdjusters.lastDayOfYear()).atTime(LocalTime.MAX);
            }
        }
        return date;
    }

    @SneakyThrows
    public static LocalDateTime getStartDate(String statisticsMode, String solidifyDateStart) {
        LocalDateTime date = null;
        if (StringUtils.hasLength(solidifyDateStart)) {
            if (StringUtils.pathEquals(statisticsMode, "day")) {
                date = DateUtils.parseDate(solidifyDateStart, "yyyy", "yyyy-MM", "yyyy-MM-dd")
                        .toInstant().atZone(ZoneId.systemDefault()).toLocalDate().atTime(LocalTime.MIN);
            } else if (StringUtils.pathEquals(statisticsMode, "month")) {
                LocalDate localDate = DateUtils.parseDate(solidifyDateStart, "yyyy", "yyyy-MM", "yyyy-MM-dd")
                        .toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                date = YearMonth.from(localDate).atDay(1).atTime(LocalTime.MIN);
            }
            if (StringUtils.pathEquals(statisticsMode, "year")) {
                int year = DateUtils.parseDate(solidifyDateStart, "yyyy", "yyyy-MM", "yyyy-MM-dd")
                        .toInstant().atZone(ZoneId.systemDefault()).getYear();
                date = LocalDateTime.of(year, 1, 1, 0, 0, 0);
            }
        }
        return date;
    }

    @Resource
    private IProductTypeService productTypeService;

    @ApiOperation("碳减总览查询")
    @GetMapping("carbonReductionOverview")
    public ResultResp<Map<String, Object>> carbonReductionOverview(String sceneProjectId,
                                                                   String sceneEdificeId,
                                                                   String sceneFloorId,
                                                                   String sceneRoomId,
                                                                   String statisticsMode,
                                                                   String solidifyDateStart, String solidifyDateEnd) {
        List<ProductTypeEntity> list = productTypeService.list(new LambdaQueryWrapper<ProductTypeEntity>()
                .eq(ProductTypeEntity::getActiveStatus, ProductTypeActiveStatus.ENABLED.getValue())
                .orderByAsc(ProductTypeEntity::getProductTypeCode));

        LocalDateTime start = getStartDate(statisticsMode, solidifyDateStart);
        LocalDateTime end = getEndDate(statisticsMode, solidifyDateEnd);
        List<EnergyDataEntity> dataList = Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder
                        .add("ecp_tt_energy_data.product_type_id", "productTypeId", false)
                        .add("SUM(meter_value)", "meterValue", false)
                        .add("SUM(carbon_emission)", "carbonEmission", false))
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .in(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), EnergyDataEntity::getSceneRoomId, sceneRoomId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EnergyDataEntity::getSolidifyDate, end)
                .groupBy(EnergyDataEntity::getProductTypeId).joinList(EnergyDataEntity.class);
        List<Map<String, Object>> resultData = new ArrayList<>(list.size());
        for (ProductTypeEntity productType : list) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", productType.getId());
            map.put("productTypeName", productType.getProductTypeName());
            EnergyDataEntity dataEntity = dataList.stream().filter(item -> productType.getId().equals(item.getProductTypeId()))
                    .findFirst().orElse(null);
            BigDecimal meterValue = BigDecimal.ZERO;
            BigDecimal carbonEmission = BigDecimal.ZERO;
            if (Objects.nonNull(dataEntity)) {
                meterValue = dataEntity.getMeterValue();
                carbonEmission = dataEntity.getCarbonEmission();
            }
            map.put("meterValue", meterValue.setScale(2, RoundingMode.HALF_UP));
            map.put("carbonEmission", carbonEmission.setScale(2, RoundingMode.HALF_UP));
            resultData.add(map);
        }
        Map<String, Object> result = new HashMap<>();
        result.put("dataList", resultData);
        result.put("startDate", Objects.isNull(start) ? null : start.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
        result.put("endDate", end.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
        return ResultResp.success(result);
    }

    @ApiOperation("碳减趋势查询")
    @GetMapping("carbonReductionTrend")
    public ResultResp<List<Map<String, Object>>> carbonReductionTrend(String sceneProjectId,
                                                                      String sceneEdificeId,
                                                                      String sceneFloorId,
                                                                      String sceneRoomId,
                                                                      String statisticsMode,
                                                                      String solidifyDateStart, String solidifyDateEnd) {
        LocalDateTime start = getStartDate(statisticsMode, solidifyDateStart);
        LocalDateTime end = getEndDate(statisticsMode, solidifyDateEnd);
        List<EnergyDataEntity> dataList = Joins.of(EnergyDataEntity.class)
                .selectAll()
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .in(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .isNotNull(EnergyDataEntity::getProductTypeId)
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getEnergyTypeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneEdificeId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), EnergyDataEntity::getSceneFloorId, sceneRoomId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EnergyDataEntity::getSolidifyDate, end)
                .joinList(EnergyDataEntity.class);
        Map<String, List<EnergyDataEntity>> dateMap = dataList.stream()
                .collect(Collectors.groupingBy(item -> DateUtil.format(item.getSolidifyDate(), "yyyy-MM-dd"), TreeMap::new, Collectors.toList()));
        List<Map<String, Object>> result = new ArrayList<>(dateMap.size());
        for (Map.Entry<String, List<EnergyDataEntity>> entry : dateMap.entrySet()) {
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("solidifyDate", entry.getKey());
            Map<String, List<EnergyDataEntity>> productTypeMap = entry.getValue().stream().collect(Collectors.groupingBy(EnergyDataEntity::getProductTypeId));
            BigDecimal total = BigDecimal.ZERO;
            for (Map.Entry<String, List<EnergyDataEntity>> energyTypeEntry : productTypeMap.entrySet()) {
                BigDecimal value = energyTypeEntry.getValue().stream().map(EnergyDataEntity::getCarbonEmission).reduce(BigDecimal.ZERO, BigDecimal::add);
                dataMap.put(energyTypeEntry.getKey(), value);
                total = total.add(value);
            }
            dataMap.put("total", total.setScale(2, RoundingMode.HALF_UP));
            result.add(dataMap);
        }
        return ResultResp.success(result);
    }

    @ApiOperation("碳汇情况分析查询")
    @GetMapping("carbonSinkOverview")
    public ResultResp<Map<String, Object>> carbonSinkOverview(String sceneProjectId,
                                                              String sceneEdificeId,
                                                              String sceneFloorId,
                                                              String sceneRoomId,
                                                              String statisticsMode,
                                                              String solidifyDateStart, String solidifyDateEnd) {
        LocalDateTime start = getStartDate(statisticsMode, solidifyDateStart);
        LocalDateTime end = getEndDate(statisticsMode, solidifyDateEnd);
        List<CarbonSinkDataEntity> list = carbonSinkDataService.query()
                .select("type", "SUM(area) AS area", "SUM(carbon_emission) AS carbonEmission")
                .eq(StringUtils.hasLength(sceneProjectId), "scene_project_id", sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), "scene_edifice_id", sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), "scene_floor_id", sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), "scene_room_id", sceneRoomId)
                .ge(Objects.nonNull(start), "solidify_date", start)
                .le(Objects.nonNull(end), "solidify_date", end)
                .groupBy("type").list();
        List<Map<String, Object>> resultData = new ArrayList<>(list.size());
        for (CarbonSinkDataEntity productType : list) {
            Map<String, Object> map = new HashMap<>();
            map.put("type", productType.getType());
            map.put("area", productType.getArea());
            map.put("carbonEmission", productType.getCarbonEmission().setScale(2, RoundingMode.HALF_UP));
            resultData.add(map);
        }
        Map<String, Object> result = new HashMap<>(3);
        result.put("dataList", resultData);
        result.put("startDate", Objects.isNull(start) ? null : start.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
        result.put("endDate", end.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
        return ResultResp.success(result);
    }


    @Resource
    private ICarbonPriceDataService carbonPriceDataService;

    @ApiOperation("碳价情况查询")
    @GetMapping("carbonPrice")
    public ResultResp<Map<String, Object>> carbonPrice(String sceneProjectId,
                                                       String statisticsMode,
                                                       String solidifyDateStart, String solidifyDateEnd) {
        LocalDateTime start = getStartDate(statisticsMode, solidifyDateStart);
        LocalDateTime end = getEndDate(statisticsMode, solidifyDateEnd);
        List<CarbonPriceDataEntity> list = carbonPriceDataService.query()
                .eq(StringUtils.hasLength(sceneProjectId), "scene_project_id", sceneProjectId)
                .ge(Objects.nonNull(start), "data_time", start)
                .le(Objects.nonNull(end), "data_time", end)
                .orderByAsc("data_time")
                .list();
        List<Map<String, Object>> resultData = new ArrayList<>(list.size());
        Map<String, List<CarbonPriceDataEntity>> dateMap;
        if (StringUtils.pathEquals(statisticsMode, "year")) {
            dateMap = list.stream().collect(Collectors.groupingBy(item -> String.valueOf(item.getDataTime().toLocalDate().getYear()),
                    TreeMap::new, Collectors.toList()));
        } else if (StringUtils.pathEquals(statisticsMode, "month")) {
            dateMap = list.stream().collect(Collectors.groupingBy(item -> item.getDataTime().toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM")),
                    TreeMap::new, Collectors.toList()));
        } else {
            dateMap = list.stream().collect(Collectors.groupingBy(item -> item.getDataTime().toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
                    TreeMap::new, Collectors.toList()));
        }
        for (Map.Entry<String, List<CarbonPriceDataEntity>> entry : dateMap.entrySet()) {
            Map<String, List<CarbonPriceDataEntity>> projectDataMap = entry.getValue().stream().collect(Collectors.groupingBy(CarbonPriceDataEntity::getSceneProjectId));
            for (Map.Entry<String, List<CarbonPriceDataEntity>> projectEntry : projectDataMap.entrySet()) {
                BigDecimal totalCarbonQuotaPrice = projectEntry.getValue().stream().map(CarbonPriceDataEntity::getCarbonQuotaPrice).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal ccerPrice = projectEntry.getValue().stream().map(CarbonPriceDataEntity::getCcerPrice).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                Map<String, Object> map = new HashMap<>();
                map.put("solidifyDate", entry.getKey());
                map.put("sceneProjectId", projectEntry.getKey());
                map.put("ccerPrice", computePrice(entry.getKey(), ccerPrice));
                map.put("carbonQuotaPrice", computePrice(entry.getKey(), totalCarbonQuotaPrice));
                resultData.add(map);
            }
        }
        Map<String, Object> result = new HashMap<>(3);
        result.put("dataList", resultData);
        result.put("startDate", Objects.isNull(start) ? null : start.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
        result.put("endDate", end.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
        return ResultResp.success(result);
    }

    private BigDecimal computePrice(String date, BigDecimal ccerPrice) {
        if (date.length() == 4) { // yyyy
            Year year = Year.parse(date, DateTimeFormatter.ofPattern("yyyy"));
            return ccerPrice.divide(new BigDecimal(String.valueOf(year.length())), RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);
        } else if (date.length() == 7) { //yyyy-MM
            YearMonth yearMonth = YearMonth.parse(date, DateTimeFormatter.ofPattern("yyyy-MM"));
            return ccerPrice.divide(new BigDecimal(String.valueOf(yearMonth.lengthOfMonth())), RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);
        } else {
            LocalDate localDate = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            return ccerPrice.divide(new BigDecimal(String.valueOf(localDate.getDayOfMonth())), RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);
        }
    }

    @Resource
    private ICarbonQuotaService carbonQuotaService;

    @ApiOperation("碳配额查询")
    @GetMapping("carbonQuota")
    public ResultResp<Map<String, Object>> carbonQuota(String sceneProjectId,
                                                       String sceneEdificeId,
                                                       String sceneFloorId,
                                                       String sceneRoomId,
                                                       String statisticsMode,
                                                       String solidifyDateStart, String solidifyDateEnd) {
        LocalDateTime start = getStartDate(statisticsMode, solidifyDateStart);
        LocalDateTime end = getEndDate(statisticsMode, solidifyDateEnd);
        Map<String, Object> result = new HashMap<>(2);
        BigDecimal usedValue = getUsedValue(sceneProjectId, sceneEdificeId, sceneFloorId, sceneRoomId, start, end);
        result.put("usedValue", usedValue);
        List<CarbonQuotaResp> list = carbonQuotaService.lambdaQuery()
                .eq(StringUtils.hasLength(sceneProjectId), CarbonQuotaEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), CarbonQuotaEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), CarbonQuotaEntity::getSceneFloorId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), CarbonQuotaEntity::getSceneRoomId, sceneRoomId)
                .ge(Objects.nonNull(start), CarbonQuotaEntity::getCreateTm, start)
                .le(Objects.nonNull(end), CarbonQuotaEntity::getCreateTm, end)
                .orderByAsc(CarbonQuotaEntity::getCreateTm)
                .list().stream().map(item -> {
                    CarbonQuotaResp carbonQuotaResp = new CarbonQuotaResp();
                    carbonQuotaResp.setId(item.getId());
                    carbonQuotaResp.setSceneProjectId(item.getSceneProjectId());
                    carbonQuotaResp.setCreateTm(item.getCreateTm());
                    carbonQuotaResp.setQuotaValue(item.getQuotaValue());
                    carbonQuotaResp.setInputType(item.getInputType());
                    carbonQuotaResp.setCarbonIncome(Objects.isNull(item.getCarbonIncome()) ? carbonQuotaService.calculateCarbonIncome(item.getSceneProjectId(),
                            item.getInputType(), item.getQuotaValue(), item.getCreateTm())
                            : item.getCarbonIncome());
                    return carbonQuotaResp;
                }).collect(Collectors.toList());
        result.put("dataList", list);
        return ResultResp.success(result);
    }

    private BigDecimal getUsedValue(String sceneProjectId, String sceneEdificeId, String sceneFloorId,
                                    String sceneRoomId, LocalDateTime start, LocalDateTime end) {
        BigDecimal res = Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder
                        .add("SUM(carbon_emission)", "carbonEmission", false)
                )
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .notIn(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getEnergyTypeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneEdificeId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), EnergyDataEntity::getSceneFloorId, sceneRoomId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EnergyDataEntity::getSolidifyDate, end)
                .joinGetOne(BigDecimal.class);
        return Objects.isNull(res) ? BigDecimal.ZERO : res;
    }


    @Resource
    private ICarbonCCERService carbonCCERService;

    @ApiOperation("CCER查询")
    @GetMapping("ccer")
    public ResultResp<List<CarbonCCERResp>> ccer(String sceneProjectId,
                                                 String sceneEdificeId,
                                                 String sceneFloorId,
                                                 String sceneRoomId,
                                                 String statisticsMode,
                                                 String solidifyDateStart, String solidifyDateEnd) {
        LocalDateTime start = getStartDate(statisticsMode, solidifyDateStart);
        LocalDateTime end = getEndDate(statisticsMode, solidifyDateEnd);
        List<CarbonCCERResp> list = carbonCCERService.lambdaQuery()
                .eq(StringUtils.hasLength(sceneProjectId), CarbonCCEREntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), CarbonCCEREntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), CarbonCCEREntity::getSceneFloorId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), CarbonCCEREntity::getSceneRoomId, sceneRoomId)
                .ge(Objects.nonNull(start), CarbonCCEREntity::getCreateTm, start)
                .le(Objects.nonNull(end), CarbonCCEREntity::getCreateTm, end)
                .orderByAsc(CarbonCCEREntity::getCreateTm)
                .list().stream().map(item -> {
                    CarbonCCERResp carbonCCERResp = new CarbonCCERResp();
                    carbonCCERResp.setId(item.getId());
                    carbonCCERResp.setSceneProjectId(item.getSceneProjectId());
                    carbonCCERResp.setCreateTm(item.getCreateTm());
                    carbonCCERResp.setCcerValue(item.getCcerValue().setScale(2, RoundingMode.HALF_UP));
                    carbonCCERResp.setInputType(item.getInputType());
                    // 参考： io.itit.ecp.admin.provide.action.controller.CarbonCCERController.queryPage
                    if (!StringUtils.pathEquals(item.getInputType(), CarbonQuotaInputTypeEnums.ADD.getValue())) {
                        List<CarbonPriceDataEntity> priceDateList = carbonPriceDataService.list(new LambdaQueryWrapper<CarbonPriceDataEntity>()
                                .eq(CarbonPriceDataEntity::getSceneProjectId, item.getSceneProjectId())
                                .ge(CarbonPriceDataEntity::getDataTime, DateUtil.beginOfDay(item.getCreateTm()))
                                .le(CarbonPriceDataEntity::getDataTime, DateUtil.endOfDay(item.getCreateTm()))
                                .orderByDesc(CarbonPriceDataEntity::getDataTime)
                        );
                        if (!priceDateList.isEmpty()) {
                            carbonCCERResp.setCarbonIncome(priceDateList.get(0).getCcerPrice().multiply(item.getCcerValue()));
                            if (StringUtils.pathEquals(item.getInputType(), CarbonQuotaInputTypeEnums.PURCHASE.getValue())) { //购入为负数
                                carbonCCERResp.setCarbonIncome(carbonCCERResp.getCarbonIncome().negate().setScale(2, RoundingMode.HALF_UP));
                            }
                        }
                    }
                    return carbonCCERResp;
                }).collect(Collectors.toList());
        return ResultResp.success(list);
    }
}
